#coding=utf-8
import logging
import sys
import json
import os
from util_base.common_utils import ComplexEncoder
from protobuf_base import protobuf
import traceback



if hasattr(sys, 'frozen'):
    _srcfile = "util%slogging_utils%s" % (os.sep, __file__[-4:])
elif __file__[-4:].lower() in ['.pyc', '.pyo']:
    _srcfile = __file__[:-4] + '.py'
else:
    _srcfile = __file__
_srcfile = os.path.normcase(_srcfile)

class Tracker(object):
    '''
    log tracker, to record things happened in one HTTP request 
    '''
    
    def __init__(self, logger='track'):
        '''
        '''
        
        self.logger = logging.getLogger(logger)
        # 因为这里封装了logger, 所以记录日志时查找上一帧的时候会找到本类中的方法, 导致无法正确记录调用者的file, func和lineno
        # 此处修正这个问题
#         self.logger.findCaller = self._findCaller
        
        self._bufs = ['']

    def logging_request_header(self, handler, buf=True):
        '''
        append record request header in log file
        '''
    
        try:
            header_msg = json.dumps(handler.request.headers)
        except:
            try:
                header_msg = json.dumps(handler.request.headers._dict)
            except:
                self.trace_error()
        
        content = self._assemble_msg('RequestHeader', header_msg)
        if not buf:
            self.logger.info(content)
        else:
            self._bufs.append(content)
            
    def logging_request_body(self, handler, parsed_body=None, text=None, buf=True):
        '''
        record request header in log file
        '''
        
        assert parsed_body or text
        try:
            if parsed_body is None:
                body_msg = text.replace('\n', '')
            else:
                body_msg = json.dumps(parsed_body, cls=protobuf.LogEncoder, ensure_ascii=False).replace('\n', '')
            
            content = self._assemble_msg('RequestBody', body_msg)
            if not buf:
                self.logger.info(content)
            else:
                self._bufs.append(content)
        except:
            self.trace_error()
        
    def logging_response(self, handler, res, buf=True):
        '''
        record response in log file
        '''
        
        try:
            # 修改bug  保存日志后解析错误,有中文以及含有包含字典或列表的字符串
            response_msg = json.dumps(res, cls=ComplexEncoder, ensure_ascii=False).replace('\n', '')
            content = self._assemble_msg('ResponseMsg', response_msg)
            if not buf:
                self.logger.info(content)
            else:
                self._bufs.append(content)
        except:
            self.trace_error()
            
    def _assemble_msg(self, msg_tag, msg_body):
            '''
            组织消息体
                
            Args:
                msg_tag : 消息标识
                msg_body ：消息体
            '''
        
            # format : tag:msg_body
            return '%s:%s' % (msg_tag, msg_body)
        
    def trace_error(self, tag='', buf=True):
        '''
        record exception stack in log file
        '''
        
        
        etype, evalue, tracebackObj = sys.exc_info()[:3]
        if not buf:
            string = 'Type: %s\nValue: %s'
            content = string %(etype, evalue)
            self.logger.exception('ErrorStack:\n' + content)
        else:
            self._bufs.append('ErrorStack:')
            self._bufs.append('  Type: %s'% (etype))
            self._bufs.append('  Value: %s'% (evalue))
            traceback.print_tb(tracebackObj, file=self)
    
    def info(self, msg, tag='', buf=True):
        '''
        info
        '''
        
        if tag:
            content = '%s:%s'% (tag, msg)
        else:
            content = msg
        
        if not buf:
            self.logger.info(content)
        else:
            self._bufs.append(content)
    
    def debug(self, msg, tag='', buf=True):
        '''
        debug
        '''
        
        if tag:
            content = '%s:%s'% (tag, msg)
        else:
            content = msg
        
        if not buf:
            self.logger.debug(content)
        else:
            self._bufs.append(content)
    
    def error(self, msg, tag='', buf=True):
        '''
        error
        '''
        
        if tag:
            content = '%s:%s'% (tag, msg)
        else:
            content = msg
        
        if not buf:
            self.logger.error(content)
        else:
            self._bufs.append(content)
    
    def warn(self, msg, tag='', buf=True):
        '''
        warning
        '''
        
        if tag:
            content = '%s:%s'% (tag, msg)
        else:
            content = msg
        
        if not buf:
            self.logger.warn(content)
        else:
            self._bufs.append(content)
            
    def flush(self):
        '''
        '''
        
        msg = '\n        '.join(self._bufs)
        self._bufs = ['']
        
        self.logger.info(msg)
        
    def write(self, msg):
        
        self._bufs.append(msg.replace('\n', ''))
            
    def _findCaller(self):
        '''
        获取调用者信息, 用于记录file func lineno
        '''
        
        f = logging.currentframe()

        if f is not None:
            f = f.f_back.f_back
        rv = "(unknown file)", 0, "(unknown function)"
        while hasattr(f, "f_code"):
            co = f.f_code
            filename = os.path.normcase(co.co_filename)
            if filename == _srcfile:
                f = f.f_back
                continue
            rv = (co.co_filename, f.f_lineno, co.co_name)
            break
        return rv
